﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    My_client = new QModbusTcpClient();
    connect(ui->pushButton, &QPushButton::clicked, [=](){
       Connect_to_modbus("192.168.0.45", 1502);
    });
    connect(ui->actionexit, &QAction::triggered, [=](){
        this->close();
    });
    connect(this, &MainWindow::statechange_on, [=](){
        statusBar()->showMessage(tr("连接成功"),5000);
    });
    connect(this, &MainWindow::statechange_off, [=](){
        statusBar()->showMessage(tr("断开连接"),5000);

    });

    qDebug() << "start";


    //连接状态改变执行处理函数
    connect(My_client,&QModbusClient::stateChanged, this, &MainWindow::StateChangeHandler);


}

bool MainWindow::Connect_to_modbus(QString IP_address, int Port)
{
    qDebug() << "开始连接" << My_client->state();
    if(!My_client){
        return false;
    }

    if(My_client->state() != QModbusDevice::ConnectedState)//判断当前连接是否为断开状态
    {
        //配置modubs tcp的连接参数IP Port
        My_client->setConnectionParameter(QModbusDevice::NetworkAddressParameter, IP_address);
        My_client->setConnectionParameter(QModbusDevice::NetworkPortParameter, Port);

        My_client->connectDevice();//连接设备

        qDebug() << "连接后状态" << My_client->state();
        return true;
    }
    else
    {
        My_client->disconnectDevice();
        return false;
    }

}

void MainWindow::StateChangeHandler()
{
    if(My_client->state() == QModbusDevice::ConnectedState)
    {
        emit statechange_on();

        readtime = new QTimer(this);
        readtime->start(10000);//每隔10s发送一次读取请求
        connect(readtime, &QTimer::timeout, [=](){
             readRequest();
        });


    }
    else if(My_client->state() == QModbusDevice::UnconnectedState)
    {

        emit statechange_off();
        readtime->stop();//modbus设备断开，定时器停止

    }


}

void MainWindow::readRequest()
{
    if (!My_client)
        return;


    QModbusDataUnit ReadUnit(QModbusDataUnit::HoldingRegisters,0,1);//发送读取保持寄存器，从0地址开始的连续两个寄存器
    if (auto *reply = My_client->sendReadRequest(ReadUnit, 1)) {//1为服务器的id
        if (!reply->isFinished())
            connect(reply, &QModbusReply::finished, this, &MainWindow::readReady);
        else
            delete reply; // broadcast replies return immediately
    } else {
        statusBar()->showMessage(tr("Read error: ") + My_client->errorString(), 5000);
    }
}

void MainWindow::readReady()
{
    auto reply = qobject_cast<QModbusReply *>(sender());
    if (!reply)
        return;


    if (reply->error() == QModbusDevice::NoError) {
        const QModbusDataUnit unit = reply->result();
//        for (uint i = 0; i < unit.valueCount(); i++) {
//            const QString entry = tr("Address: %1, Value: %2").arg(unit.startAddress())
//                                     .arg(QString::number(unit.value(i),
//                                          unit.registerType() <= QModbusDataUnit::Coils ? 10 : 16));
            const QString value0  = tr("%1").arg(QString::number(unit.value(0),unit.registerType() <= QModbusDataUnit::HoldingRegisters ? 10 : 16));
            int vlint = value0.toInt()/10;
            float vfloat = value0.toInt()%10;
            QString showvalue = QString("%1.%2").arg(vlint).arg(vfloat);
            ui->label->setText(showvalue);
//        }
    } else if (reply->error() == QModbusDevice::ProtocolError) {
        statusBar()->showMessage(tr("Read response error: %1 (Mobus exception: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->rawResult().exceptionCode(), -1, 16), 5000);
    } else {
        statusBar()->showMessage(tr("Read response error: %1 (code: 0x%2)").
                                    arg(reply->errorString()).
                                    arg(reply->error(), -1, 16), 5000);
    }

    reply->deleteLater();
}


MainWindow::~MainWindow()
{
    delete ui;
}
